use std::path::PathBuf;

use serde::{Deserialize, Serialize};

use crate::app::FileProcessResult;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PublishedFileRecord {
    pub file_id: u64,
    pub original_file_name: String,
    pub chunks_directory: PathBuf,
    pub public: bool,
}

/// PublicPublishedFile is the data that will be published to the gossipsub network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct PublicPublishedFile {
    pub file_id: u64,
    pub original_file_name: String,
}

impl PublishedFileRecord {
    pub fn new(
        file_id: u64,
        original_file_name: String,
        chunks_directory: PathBuf,
        public: bool,
    ) -> Self {
        Self {
            file_id,
            original_file_name,
            chunks_directory,
            public,
        }
    }

    pub fn key(&self) -> Vec<u8> {
        self.file_id.to_be_bytes().to_vec()
    }
}

impl From<&PublishedFileRecord> for PublicPublishedFile {
    fn from(value: &PublishedFileRecord) -> Self {
        Self {
            file_id: value.file_id,
            original_file_name: value.original_file_name.clone(),
        }
    }
}

impl TryFrom<&PublicPublishedFile> for Vec<u8> {
    type Error = serde_cbor::Error;

    fn try_from(value: &PublicPublishedFile) -> Result<Self, Self::Error> {
        serde_cbor::to_vec(value)
    }
}

impl TryFrom<PublicPublishedFile> for Vec<u8> {
    type Error = serde_cbor::Error;

    fn try_from(value: PublicPublishedFile) -> Result<Self, Self::Error> {
        serde_cbor::to_vec(&value)
    }
}

impl TryFrom<Vec<u8>> for PublicPublishedFile {
    type Error = serde_cbor::Error;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        serde_cbor::from_slice(&value)
    }
}

impl TryFrom<&PublishedFileRecord> for Vec<u8> {
    type Error = serde_cbor::Error;

    fn try_from(value: &PublishedFileRecord) -> Result<Self, Self::Error> {
        serde_cbor::to_vec(value)
    }
}

impl TryFrom<PublishedFileRecord> for Vec<u8> {
    type Error = serde_cbor::Error;

    fn try_from(value: PublishedFileRecord) -> Result<Self, Self::Error> {
        serde_cbor::to_vec(&value)
    }
}

impl TryFrom<Vec<u8>> for PublishedFileRecord {
    type Error = serde_cbor::Error;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        serde_cbor::from_slice(&value)
    }
}

impl From<FileProcessResult> for PublishedFileRecord {
    fn from(value: FileProcessResult) -> Self {
        Self {
            file_id: value.hash_id(),
            original_file_name: value.original_file_name,
            chunks_directory: value.chunks_directory,
            public: value.public,
        }
    }
}
